package com.sh.data.engine.domain.workspace.manager.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sh.data.engine.common.exception.BusinessException;
import com.sh.data.engine.common.util.AESUtil;
import com.sh.data.engine.domain.base.model.UserContext;
import com.sh.data.engine.domain.util.ConvertUtil;
import com.sh.data.engine.domain.workspace.manager.model.domain.MailNoticeDomain;
import com.sh.data.engine.domain.workspace.manager.model.domain.UserDomain;
import com.sh.data.engine.domain.workspace.manager.model.param.MailNoticeParam;
import com.sh.data.engine.domain.workspace.manager.service.UserService;
import com.sh.data.engine.repository.dao.workspace.manager.MailNoticeMapper;
import com.sh.data.engine.repository.dao.workspace.manager.entity.MailNoticeEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.util.NamedThreadFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.*;

/**
 * @author : mingxi.xpb
 * @date : 2021/12/29 11:32
 */
@Slf4j
@Service
public class MailNoticeService extends ServiceImpl<MailNoticeMapper, MailNoticeEntity> {
    @Autowired
    private MailNoticeMapper mailNoticeMapper;

    @Autowired
    private UserService userService;

    private static final ExecutorService pool =
        new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors(),
            Runtime.getRuntime().availableProcessors(),
            0,
            TimeUnit.MICROSECONDS,
            new LinkedBlockingQueue<>(100),
            new NamedThreadFactory("mailNotice-pool"),
            new ThreadPoolExecutor.AbortPolicy());

    /**
     * description 保存或编辑邮件配置信息
     *
     * @author : mingxi.xpb
     * @date : 2022/1/14 11:25
     */
    public void saveMailNoticeConfig(MailNoticeParam mailNoticeParam, String userId) {

        LambdaQueryWrapper<MailNoticeEntity> eq =
            new LambdaQueryWrapper<MailNoticeEntity>().eq(MailNoticeEntity::getCreatorId, userId);

        MailNoticeEntity mailNoticeMapperOne = mailNoticeMapper.selectOne(eq);

        MailNoticeEntity mailNoticeEntity =
            ConvertUtil.copyProperties(mailNoticeParam, MailNoticeEntity.class);
        if (mailNoticeMapperOne != null) { // 更新
            mailNoticeEntity.setUpdaterId(userId);
            mailNoticeEntity.setId(mailNoticeMapperOne.getId());
            mailNoticeMapper.updateById(mailNoticeEntity);
//            LogContext.put(LogKey.ISUPDATE.getKey(), LogKey.ISUPDATE.getValue());
        } else { // 新增
            mailNoticeEntity.setCreatorId(userId);
            mailNoticeEntity.setUpdaterId(userId);

            mailNoticeMapper.insert(mailNoticeEntity);
        }
    }

    /**
     * description 测试邮件服务连通性
     *
     * @author : mingxi.xpb
     * @date : 2022/1/14 11:25
     */
    public void testMailService(String mailAddress) {
        MailNoticeDomain detailMailConfig = getDetailMailConfig(UserContext.getUserId());
        if (detailMailConfig == null) {
            throw new BusinessException("未设置邮件服务配置");
        }
        JavaMailSender mailSender = getJavaMailSender(detailMailConfig);

        SimpleMailMessage message = new SimpleMailMessage();

        message.setFrom(detailMailConfig.getUsername());
        message.setTo(mailAddress);
        message.setSubject("连通性测试");
        message.setText("请确认是否收到邮件");

        Future<?> submit =
            pool.submit(
                () -> {
                    mailSender.send(message);
                    log.info("连通性测试邮件已经发送");
                });

        try {
            // 任务执行超过20s直接打断
            submit.get(20, TimeUnit.SECONDS);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            // 任务执行超过20秒，默认失败
            submit.cancel(true);
            log.error("邮件发送失败：{}", e.getMessage());
            throw new BusinessException("邮件发送失败,请检查邮件服务配置是否正确");
        }
    }

    /**
     * @description : 获取通知人信息List 去查询mail_notice
     * @author : tinglan.ys
     * @date : 2022/3/30
     */
    public List<UserDomain> getReceiver() {
        // List<MailNoticeEntity> all = mailNoticeMapper.findAll();

        List<MailNoticeEntity> list = this.list();
        List<UserDomain> userDomainList = new ArrayList<>();
        for (MailNoticeEntity mailNoticeEntity : list) {
            UserDomain userDomain = new UserDomain();
            // mail_notice表的Username就是邮箱的地址
            userDomain.setEmail(mailNoticeEntity.getUsername());
            // mail_notice表的CreatorId就是邮箱的拥有者
            userDomain.setId(mailNoticeEntity.getCreatorId());
            UserDomain userById = userService.getUserById(mailNoticeEntity.getCreatorId());
            if (userById != null) {
                userDomain.setUserName(userById.getUserName());
            }
            userDomainList.add(userDomain);
        }
        return userDomainList;
    }

    /**
     * @description : 发送邮件通用方法
     * @author : tinglan.ys
     * @date : 2022/3/30
     */
    public void sendMailService(String userId, String subject, String text) {
        // to
        MailNoticeDomain sendTo = getDetailMailConfig(userId);
        if (sendTo == null) {
            throw new BusinessException("收件人未设置邮件服务配置");
        }
        // from
        MailNoticeDomain detailMailConfig = getDetailMailConfig(UserContext.getUserId());
        if (detailMailConfig == null) {
            throw new BusinessException("发件人未设置邮件服务配置");
        }
        JavaMailSender mailSender = getJavaMailSender(detailMailConfig);

        SimpleMailMessage message = new SimpleMailMessage();

        message.setFrom(detailMailConfig.getUsername());
        // 用户绑定了一个邮箱地址
        message.setTo(sendTo.getUsername());
        message.setSubject(subject);
        message.setText(text);

        Future<?> submit =
            pool.submit(
                () -> {
                    mailSender.send(message);
                    log.info("邮件已经发送至" + detailMailConfig.getUsername());
                });

        try {
            // 任务执行超过20s直接打断
            submit.get(20, TimeUnit.SECONDS);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            // 任务执行超过20秒，默认失败
            submit.cancel(true);
            log.error("邮件发送失败：{}", e.getMessage());
            throw new BusinessException("邮件发送失败,请检查邮件服务配置是否正确");
        }
    }

    /**
     * @description : 发送邮件通用方法2
     * @author : tinglan.ys
     * @date : 2022/3/30
     */
    public void sendMailService2(String sendFrom, String sendTo, String subject, String text) {

        // from
        MailNoticeDomain detailMailConfig = getDetailMailConfig(sendFrom);
        if (detailMailConfig == null) {
            throw new BusinessException("发件人未设置邮件服务配置");
        }
        JavaMailSender mailSender = getJavaMailSender(detailMailConfig);

        SimpleMailMessage message = new SimpleMailMessage();

        message.setFrom(detailMailConfig.getUsername());
        // 用户绑定了一个邮箱地址
        message.setTo(sendTo);
        message.setSubject(subject);
        message.setText(text);

        Future<?> submit =
            pool.submit(
                () -> {
                    mailSender.send(message);
                    log.info("邮件已经发送至" + sendTo);
                });

        try {
            // 任务执行超过20s直接打断
            submit.get(20, TimeUnit.SECONDS);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            // 任务执行超过20秒，默认失败
            submit.cancel(true);
            log.error("邮件发送失败：{}", e.getMessage());
            throw new BusinessException("邮件发送失败,请检查邮件服务配置是否正确");
        }
    }

    /**
     * description 获取邮件配置详情
     *
     * @author : mingxi.xpb
     * @date : 2022/1/14 11:25
     */
    public MailNoticeDomain getDetailMailConfig(String userId) {
        //    MailNoticeEntity mailNoticeMapperOne =
        //        mailNoticeMapper.findOne(new Query(Criteria.where("creatorId").is(userId)));

        LambdaQueryWrapper<MailNoticeEntity> eq =
            new LambdaQueryWrapper<MailNoticeEntity>().eq(MailNoticeEntity::getCreatorId, userId);
        MailNoticeEntity mailNoticeMapperOne = mailNoticeMapper.selectOne(eq);

        if (mailNoticeMapperOne != null) {
            String decryptPassword = AESUtil.decrypt(mailNoticeMapperOne.getPassword());
            mailNoticeMapperOne.setPassword(decryptPassword);
            return ConvertUtil.copyProperties(mailNoticeMapperOne, MailNoticeDomain.class);
        } else {
            return null;
        }
    }

    /**
     * description 获取邮件发送对象
     *
     * @author : mingxi.xpb
     * @date : 2022/1/14 11:25
     */
    private JavaMailSender getJavaMailSender(MailNoticeDomain config) {

        JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();

        javaMailSender.setHost(config.getHost());
        javaMailSender.setPort(config.getPort());
        javaMailSender.setUsername(config.getUsername());
        javaMailSender.setPassword(config.getPassword());
        javaMailSender.setDefaultEncoding("utf-8");

        Properties javaMailProperties = new Properties();
        if (config.getSslEnable() != null && config.getSslEnable().equals(1)) {
            javaMailProperties.put("mail.smtp.auth", true);
            javaMailProperties.put("mail.smtp.timeout", 50000);
            javaMailProperties.put("mail.smtp.starttls.enable", true);
            javaMailProperties.setProperty("mail.smtp.port", Integer.toString(config.getPort())); // 设置端口
            javaMailProperties.put("mail.smtp.socketFactory.port", Integer.toString(config.getPort()));
            javaMailProperties.setProperty("mail.smtp.socketFactory.fallback", "false");
            javaMailProperties.setProperty(
                "mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        }
        javaMailSender.setJavaMailProperties(javaMailProperties);

        return javaMailSender;
    }
}
